#pragma once
#include "../common/net.hpp"
#include "../common/message.hpp"
/*提供Rpc请求处理回调函数
• 内部的服务管理
◦ ⽅法名称
◦ 参数信息
◦ 对外提供参数校验接⼝*/

namespace bitrpc
{
  // 先描述在组织
  namespace server
  {
    // rpc请求参数的类型
    enum class VType
    {
      BOOL = 0, // 布尔
      INTEGRAL, // 整形
      NUMERIC,  // 浮点型
      STRING,   // 字符串
      ARRAY,    // 数组
      OBJECT,   // 对象
    };
    class ServiceDescribe
    // 服务描述类；
    // 1.业务回调函数——Add（）函数
    // 2.方法名称、参数信息pair<参数字段名称，参数类型>
    // 3.返回值类型描述
    // 4.提供参数校验接口：针对请求中的参数，判断是否含有num1字段，其类型是否是整形
    // 处理逻辑：收到一个rpc请求后，取出方法名称，参数信息，根据方法名称Add找到Add服务的描述对象，
    // 先进行参数校验，没问题就调用业务回调函数处理
    {
    public:
      using ptr = std::shared_ptr<ServiceDescribe>;
      using ServiceCallback = std::function<void(const Json::Value &, Json::Value &)>;
      using ParamsDescribe = std::pair<std::string, VType>; // 参数字段信息——参数名称：参数类型

      ServiceDescribe(std::string &&method_name, ServiceCallback&& callback, 
        std::vector<ParamsDescribe>&& params_desc, VType return_type):
        _method_name(std::move(method_name)),_callback(std::move(callback)),
        _params_desc(std::move(params_desc)),_return_type(return_type)
        {}
      bool paramCheck(const Json::Value &params)//request请求中的参数对象
      {
        // 对params进行参数检验——判断所描述的参数字段是否存在，以及参数类型是否一致
        for (auto &[name, type] : _params_desc)
        {
          if (params.isMember(name) == false)
          {
            ELOG("参数字段名称校验失败！%s字段缺失", name.c_str());
            return false;
          }
          if (check(type, params[name]) == false)
          {
            ELOG("%s 参数类型校验失败！", name.c_str());
            return false;
          }
        }
        return true;
      }
      bool call(const Json::Value &params, Json::Value & result)
      {
        _callback(params,result);
        if(rtypeCheck(result)==false)
        {
          ELOG("服务对象回调处理的响应信息校验失败");
          return false;
        }
        return true;
      }
      const std::string& method()  { return _method_name; } 
    private:
      bool rtypeCheck(const Json::Value &val)
      {
        // DLOG("_return_type:%d",(int)_return_type);
        // DLOG("val:%d",(int)val.isIntegral());
        return check(_return_type,val);
      }

      bool check(VType type, const Json::Value &val)
      {
        switch (type)
        {
        case VType::BOOL:
          return val.isBool();
        case VType::INTEGRAL:
          return val.isIntegral();
        case VType::NUMERIC:
          return val.isNumeric();
        case VType::STRING:
          return val.isString();
        case VType::ARRAY:
          return val.isArray();
        case VType::OBJECT:
          return val.isObject();
        }
        return false;
      }

    private:
      std::string _method_name;  // 方法名称
      ServiceCallback _callback; // 真正的业务回调函数
      std::vector<ParamsDescribe> _params_desc;
      VType _return_type; // 将结果作为返回值类型的描述
    };
    class ServiceFactory
    {
    public:
       void setMethodName(std::string name)
       {
          _method_name = name;
       }
       void setParamsDesc(const std::string &pname,VType ptype)
       {
            _params_desc.push_back({pname,ptype});
       }
       void returnType(VType type)
       {
        _return_type = type;
       }
       void setCallback(const ServiceDescribe::ServiceCallback& callback)
       {
        _callback = callback;
       }
       ServiceDescribe::ptr build()
      {
        return std::make_shared<ServiceDescribe>(std::move(_method_name),std::move(_callback),
        std::move(_params_desc),std::move(_return_type));
      }

    private:
      std::string _method_name;                   // 方法名称
      ServiceDescribe::ServiceCallback _callback; // 真正的业务回调函数
      std::vector<ServiceDescribe::ParamsDescribe> _params_desc;
      VType _return_type; // 将结果作为返回值类型的描述
    };
    // 服务端会提供很多的服务方法，需要进行良好的管理
    // 通过hashi_map<服务方法名称，服务描述对象>很容易判断出能否提供某个服务
    class ServiceManager
    {
    public:
      using ptr = std::shared_ptr<ServiceManager>;

      void insert(ServiceDescribe::ptr service) // 增加service服务对象
      {
           std::unique_lock<std::mutex> lock(_mutex);
           _services[service->method()] = service;
      }
      ServiceDescribe::ptr select(const std::string& name) // 查找服务对象
      {
           std::unique_lock<std::mutex> lock(_mutex);
           if(_services.count(name)==0)
           {
            ELOG("没有找到该服务对象");
            return ServiceDescribe::ptr();
           }
           return _services[name];
      }
      void remove(const std::string& name) {// 删除服务对象
           std::unique_lock<std::mutex> lock(_mutex);
          _services.erase(name);
      } 
    private:
      std::mutex _mutex;
      std::unordered_map<std::string, ServiceDescribe::ptr> _services;
    };

    class RpcRoutor
    {
      // 提供两个服务：服务注册接口、提供给dispatcher模块的rpc请求处理回调函数
    public:
            using ptr = std::shared_ptr<RpcRoutor>;
       
       RpcRoutor():_service_manager(std::make_shared<ServiceManager>()){}
      // 这是注册到dispatcher里针对rpc请求进行回调处理的业务函数
      void onMessage(const bitrpc::BaseConnection::ptr& conn, bitrpc::RPCRequest::ptr &request)
      {
        // 1.查询客户端的请求方法描述——判断当前服务端能否提供所需的服务
        auto service = _service_manager->select(request->method());
        if(service.get() == nullptr)
        {
           ELOG("%s 服务未找到！",request->method().c_str());
           return response(conn,request,Json::Value(),RCODE::RCODE_NOT_FOUND_SERVICE);
        }
        // 2.进行参数检验：确定能否提供服务
        if(service->paramCheck(request->params())==false)
        {
          ELOG("%s服务参数校验失败！",request->method().c_str());
          return response(conn,request,Json::Value(),RCODE::RCODE_INVALID_PARAMS);
        }

        // 3.调用业务回调接口进行业务处理
        Json::Value result;
        if(service->call(request->params(),result)==false)
        {
          ELOG("调用业务回调接口失败");
          return response(conn,request,Json::Value(),RCODE::RCODE_INTERNAL_ERROR);

        }
        // 4.处理完毕得到结果，组织响应，向客户端发送

          return response(conn,request,result,RCODE::RCODE_OK);

      }
      void Register(const ServiceDescribe::ptr &service)
      {
        _service_manager->insert(service);
      }
     private:
     void response(const bitrpc::BaseConnection::ptr &conn, bitrpc::RPCRequest::ptr &request,
         const Json::Value &rsp, RCODE rcode)
         {
            auto resp = MessageFactory::create<bitrpc::RpcResponse>();
            resp->SetId(request->rid());
            resp->setRcode(rcode);
            resp->SetMessageType(bitrpc::MessageType::RSP_RPC);
            resp->setResult(rsp);
            DLOG("发送响应");
            conn->send(resp);
         }
    private:
      ServiceManager::ptr _service_manager;
    };
  }
}